﻿
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using ZFY.UnitOfWork.Interface;
using Castle.DynamicProxy;
using Microsoft.AspNetCore.Mvc;
using ZFY.Core;

namespace ZFY.UnitOfWork
{
    public class UnitOfWorkInterceptor : IInterceptor
    {
        private readonly IServiceScopeFactory _serviceScopeFactory;
        private readonly UnitOfWorkAsyncInterceptor _serviceSaveAsyncInterceptor;

        public UnitOfWorkInterceptor(IServiceScopeFactory serviceScopeFactory, UnitOfWorkAsyncInterceptor serviceSaveAsyncInterceptor)
        {
            _serviceScopeFactory = serviceScopeFactory;
            _serviceSaveAsyncInterceptor = serviceSaveAsyncInterceptor;
        }

        public void Intercept(IInvocation invocation)
        {
            _serviceSaveAsyncInterceptor.ToInterceptor().Intercept(invocation);
        }



    }
    public class UnitOfWorkAsyncInterceptor : IAsyncInterceptor
    {
        private readonly IZFYServiceProvider _serviceProvider;

        public UnitOfWorkAsyncInterceptor(IZFYServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        public void InterceptAsynchronous(IInvocation invocation)
        {
            if (!UnitOfWorkHelper.IsUnitOfWorkMethod(invocation.MethodInvocationTarget, out var unitOfWorkAttribute))
            {
                invocation.Proceed();
                return;
            }

            var options = CreateOptions(invocation, unitOfWorkAttribute);

            var unitOfWorkManager = _serviceProvider.GetRequiredService<IUnitOfWorkManager>();

            Console.Out.WriteLine(unitOfWorkManager.Id);
            using (var uow = unitOfWorkManager.Begin(options))
            {
                invocation.Proceed();
                AsyncHelper.RunSync(() => { return uow.CompleteAsync(); });


                return;
            }
        }

        public void InterceptAsynchronous<TResult>(IInvocation invocation)
        {
            invocation.ReturnValue = InternalInterceptAsynchronous<TResult>(invocation);
        }

        public void InterceptSynchronous(IInvocation invocation)
        {
            invocation.ReturnValue = InternalInterceptAsynchronous(invocation);
        }
        private async Task<TResult> InternalInterceptAsynchronous<TResult>(IInvocation invocation)
        {

            if (!UnitOfWorkHelper.IsUnitOfWorkMethod(invocation.MethodInvocationTarget, out var unitOfWorkAttribute))
            {
                invocation.Proceed();

                var taskResult = (Task<TResult>)invocation.ReturnValue;

                var result = await taskResult.ConfigureAwait(false);

                return result;
            }

            var options = CreateOptions(invocation, unitOfWorkAttribute);



            var unitOfWorkManager = _serviceProvider.LazyGetRequiredService<IUnitOfWorkManager>();


            using (var uow = unitOfWorkManager.Begin(options))
            {
                invocation.Proceed();
                //获取执行信息
                var taskResult = (Task<TResult>)invocation.ReturnValue;
                var result = await taskResult.ConfigureAwait(false);

                await uow.CompleteAsync();
                return result;
            }
        }
        private async Task InternalInterceptAsynchronous(IInvocation invocation)
        {
            if (!UnitOfWorkHelper.IsUnitOfWorkMethod(invocation.MethodInvocationTarget, out var unitOfWorkAttribute))
            {
                invocation.Proceed();
                var taskResult = (Task)invocation.ReturnValue;
                await taskResult.ConfigureAwait(false);

                return ;
            }

            var options = CreateOptions(invocation, unitOfWorkAttribute);

            var unitOfWorkManager = _serviceProvider.LazyGetRequiredService<IUnitOfWorkManager>();



            using (var uow = unitOfWorkManager.Begin(options))
            {
                invocation.Proceed();
                //获取执行信息
                var taskResult = (Task)invocation.ReturnValue;
                await taskResult.ConfigureAwait(false);

                await uow.CompleteAsync();
                return;
            }

        }


        private UnitOfWorkOption CreateOptions(IInvocation invocation, UnitOfWorkAttribute unitOfWorkAttribute)
        {
            var options = new UnitOfWorkOption();

            unitOfWorkAttribute?.SetOptions(options);

            if (unitOfWorkAttribute?.Scope == null)
            {
                options.Scope = !invocation.Method.Name.StartsWith("Get", StringComparison.InvariantCultureIgnoreCase) ? System.Transactions.TransactionScopeOption.Required : System.Transactions.TransactionScopeOption.Suppress;
            }

            return options;
        }
    }
}
